home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cpp_libs / awe2-0_1.lha / awe2-0.1 / Src / RCS / HardwareCpu.cc,v < prev    next >
Text File  |  1988-09-28  |  28KB  |  1,286 lines

  1. head     1.3;
  2. access   ;
  3. symbols  ;
  4. locks    ; strict;
  5. comment  @@;
  6.  
  7.  
  8. 1.3
  9. date     88.09.28.22.13.27;  author grunwald;  state Exp;
  10. branches ;
  11. next     1.2;
  12.  
  13. 1.2
  14. date     88.09.21.20.51.32;  author grunwald;  state Exp;
  15. branches ;
  16. next     1.1;
  17.  
  18. 1.1
  19. date     88.09.18.16.42.24;  author grunwald;  state Exp;
  20. branches ;
  21. next     ;
  22.  
  23.  
  24. desc
  25. @@
  26.  
  27.  
  28. 1.3
  29. log
  30. @*** empty log message ***
  31. @
  32. text
  33. @#include "HardwareCpu.h"
  34. #include "HardSpinLock.h"
  35. #include "HardBarrier.h"
  36. #include "HardFetchAndOp.h"
  37. #include "AwesimeHeap.h"
  38. #include "Thread.h"
  39. #include "HeapScheduler.h"
  40. #include "ReserveByException.h"
  41. #include <math.h>
  42.  
  43. //
  44. //    Things left to do:
  45. //
  46. //    + Add instrumentation code ifdef'd on INSTRUMENT, to measure
  47. //      the following: number of threads exec'd per clock-tick,
  48. //      time spent waiting for other CPUS, (what else?)
  49. //
  50. //    + Make all the debug stuff be conditional on DEBUG being defined
  51. //
  52. //    + Chunk the CurrentEventsList into a pile for each CPU. A
  53. //      CPU draws first from their own pile, and then from the
  54. //      piles of others.
  55. //        Advantages:    reduces lock contention
  56. //                increase cache locality
  57. //
  58. //        Disadvantages:    Pain to implement
  59. //        ** DONE **
  60. //
  61. //    + Make the ThreadHeap really use the Gnu PairingHeap structure.
  62. //      Doug Lea added an iterator class & other enhancements.
  63. //
  64. //    + Capture signals, transfer them to an Exception class. Can
  65. //      use this to implement time-slices & the like, as well as....
  66. //
  67. //    + Put in ``addCpu'' and ``removeCpu'' calls to HardwareCpu.
  68. //      This would allow run-time addition/removal of CPUS, so
  69. //      you can tailor your program to system 
  70. //        This is tricky. Should probably do it when you
  71. //        advance the clock, but it'll be tricky to get all
  72. //        the CPUs to agree on the barrier height for the
  73. //        rendezvous. Also might complicate the ``distinct
  74. //        pools of threads per cpu''.
  75. //
  76.  
  77. #ifndef umax
  78.   const static int MaxHardwareCpus = 1;
  79. #else
  80.   const static int MaxHardwareCpus = 20;
  81. #endif
  82.  
  83. int HardwareCpus;
  84. HardwareCpu *ThisCpu;
  85.  
  86. static HardBarrier CpuBarrier(0);
  87.  
  88. //
  89. //    PendingEventsLock, CurrentEventsLock and TimeAdvanceCounterLock
  90. //    must be acquired in that order, and releaseed in the reverse order.
  91. //
  92. static HardSpinLock cerrLock;
  93.  
  94. //
  95. //    The count of all all current events
  96. //
  97. static HardFetchAndOp GlobalCurrentEventsCounter(0);
  98.  
  99. //
  100. //    A currentEvents pile for each processor. The count is only correct
  101. //    if you've res'd the spin lock -- it's used as a guess.
  102. //
  103. static HardSpinLock CurrentEventsLock[MaxHardwareCpus];
  104. static int CurrentEventsCounter[MaxHardwareCpus];
  105. static ThreadContainer *CurrentEvents[MaxHardwareCpus];
  106.  
  107. //
  108. //    The PendingEvents queue is private to each processor
  109. //
  110. static AwesimeHeap *PendingEvents[MaxHardwareCpus];
  111.  
  112. static int SimulationTerminated = 0;
  113. double CurrentSimulatedTime = 0.0;
  114.  
  115. static HardFetchAndOp TimeAdvanceCounter(0);
  116.  
  117. //
  118. //    This can't be private, or we won't see all the action
  119. //
  120. int HardwareDebugFlag = 0;
  121.  
  122. HardwareCpu::HardwareCpu(int debug) : systemContext(0, 0)
  123. {
  124.     currentThread = 0;
  125.     iYam = 0;
  126.     pid = 0;
  127.     HardwareDebugFlag = debug;
  128.     allocateEventStructures(0);
  129. }
  130.  
  131. HardwareCpu::~HardwareCpu()
  132. {
  133. }
  134.  
  135. void
  136. HardwareCpu::debug(int newdebug)
  137. {
  138.     HardwareDebugFlag = newdebug;
  139. }
  140.  
  141. int
  142. HardwareCpu::debug()
  143. {
  144.     return(HardwareDebugFlag);
  145. }
  146.  
  147. void
  148. HardwareCpu::rendezvous()
  149. {
  150.     CpuBarrier.rendezvous();
  151. }
  152.  
  153. void
  154. HardwareCpu::allocateEventStructures(int newIYam)
  155. {
  156.     iYam = newIYam;
  157.     sprintf(nameSpace, "[HardwareCpu-%d] ", iYam);
  158.     name = nameSpace;
  159.  
  160.     CurrentEventsCounter[iYam] = 0;
  161.     CurrentEvents[iYam] = AllocateHardwareCurrentEventsStructure();
  162.     PendingEvents[iYam] = new AwesimeHeap(128);
  163.  
  164.     myCurrentEvents = CurrentEvents[iYam];
  165.     myCurrentEventsLock = &CurrentEventsLock[iYam];
  166.  
  167.     myPendingEvents = PendingEvents[iYam];
  168. }
  169.  
  170. void
  171. HardwareCpu::deallocateEventStructures()
  172. {
  173.     myCurrentEventsLock -> reserve();
  174.     //
  175.     //    Move remaining events to another queue
  176.     //
  177.     while ( CurrentEventsCounter[iYam] == 0 ) {
  178.     CurrentEventsLock[0].reserve();
  179.     assert(CurrentEvents[0] != 0);
  180.     CurrentEvents[0] -> add( myCurrentEvents -> remove() );
  181.     CurrentEventsCounter[0]++;
  182.     CurrentEventsCounter[iYam]--;
  183.     CurrentEventsLock[0].release();
  184.     }
  185.     delete myCurrentEvents;
  186.     myCurrentEvents = 0;
  187.     CurrentEvents[iYam] = 0;
  188.     CurrentEventsCounter[iYam] = 0;
  189.     myCurrentEventsLock -> release();
  190.  
  191.     while ( ! myPendingEvents -> isEmpty() ) {
  192.     assert(PendingEvents[0] != 0);
  193.     AwesimeHeapItem item;
  194.     if (myPendingEvents -> remove(item)) {
  195.         PendingEvents[0] -> add( item );
  196.     }
  197.     }
  198.     delete myPendingEvents;
  199.     myPendingEvents = 0;
  200.     PendingEvents[iYam] = 0;
  201. }
  202.  
  203. void
  204. HardwareCpu::fireItUp(int cpus, unsigned shared)
  205. {
  206.     assert(cpus > 0);
  207.     
  208.     if ( cpus > MaxHardwareCpus ) {
  209.     cpus = MaxHardwareCpus;
  210.     }
  211.  
  212.     HardwareCpus = cpus;
  213.     ThisCpu = this;
  214.  
  215. #ifndef NDEBUG
  216.     if (HardwareDebugFlag) {
  217.     cerrLock.reserve();
  218.     cerr << name << "Allocate " << shared << " bytes of shared memory\n";
  219.     cerrLock.release();
  220.     }
  221. #endif /* NDEBUG */
  222.  
  223.     extern void SharedMemoryInit( unsigned );
  224.     SharedMemoryInit( shared );
  225.  
  226.     //
  227.     //    Spawn the children, giving each a unique number from 0..(cpus-1).
  228.     //  The first child gets id (cpus-1), and the original process gets 0.
  229.     //
  230.  
  231.     iYam = 0;
  232. #ifndef NDEBUG
  233.     if (HardwareDebugFlag) {
  234.     cerrLock.reserve();
  235.     cerr << name << "Allocate " << HardwareCpus << "cpus\n";
  236.     cerrLock.release();
  237.     }
  238. #endif /* NDEBUG */
  239.  
  240.     CpuBarrier.height(HardwareCpus);
  241.     
  242.     for (int whoAmI = 1; whoAmI < HardwareCpus; whoAmI++) {
  243.     if (iYam == 0) {
  244.         int pid = fork();
  245.         if (pid == 0) {    // child 
  246.         allocateEventStructures(whoAmI);
  247.         break;
  248.         }
  249.     }
  250.     }
  251.     pid = getpid();
  252. #ifndef NDEBUG
  253.     if (HardwareDebugFlag) {
  254.     cerrLock.reserve();
  255.     cerr << name << "I am now id " << iYam << " and pid " << pid <<" \n";
  256.     cerrLock.release();
  257.     }
  258. #endif /* NDEBUG */
  259.     rendezvous();
  260. }
  261.  
  262. void
  263. HardwareCpu::coolItDown()
  264. {
  265.     rendezvous();
  266.     if (iYam > 0) {
  267.     cerrLock.reserve();
  268.     cerr << name << "exit";
  269.     cerrLock.release();
  270.     _exit(0);
  271.     }
  272.     else {
  273.     //
  274.     //    reap the dead children. This way we know they are all dead.
  275.     //    The caller can then safely exit.
  276.     //
  277.     while (HardwareCpus > 1) {
  278.         int pid = wait(0);
  279.         if (pid == -1) {
  280.         perror("wait");
  281.         break;
  282.         }
  283.         HardwareCpus--;
  284.     }
  285.     //
  286.     //  In case of break in above loop
  287.     //
  288.     HardwareCpus = 1;
  289.     //
  290.     //  In case we call rendezvous again
  291.     //
  292.     CpuBarrier.height(HardwareCpus);
  293.     }
  294. }
  295.  
  296. void
  297. HardwareCpu::add(Thread *who, double when)
  298. {
  299.     if (when <= 0) {
  300. #ifndef NDEBUG
  301.     if (HardwareDebugFlag) {
  302.         cerrLock.reserve();
  303.         cerr << name << " add " << hex(long(who)) << " to current\n";
  304.         cerrLock.release();
  305.     }
  306. #endif /* NDEBUG */
  307.     //
  308.     // Add them to the list of current events
  309.     //
  310.     myCurrentEventsLock -> reserve();
  311.     myCurrentEvents -> add( who );
  312.     CurrentEventsCounter[iYam]++;
  313.     myCurrentEventsLock -> release();
  314.  
  315.     GlobalCurrentEventsCounter.add(1);
  316. #ifndef NDEBUG
  317.     if (HardwareDebugFlag) {
  318.         cerrLock.reserve();
  319.         cerr << name << " giving " << CurrentEventsCounter[iYam];
  320.         cerr << " local and " << GlobalCurrentEventsCounter.add(0);
  321.         cerr << " global\n";
  322.         cerrLock.release();
  323.     }
  324. #endif /* NDEBUG */
  325.     }
  326.     else {
  327. #ifndef NDEBUG
  328.     if (HardwareDebugFlag) {
  329.         cerrLock.reserve();
  330.         cerr << name << " add " << hex(long(who)) << " to pending\n";
  331.         cerrLock.release();
  332.     }
  333. #endif /* NDEBUG */
  334.     //
  335.     // Add them to pending events
  336.     //
  337.     when += CurrentSimulatedTime;
  338.     myPendingEvents->add( AwesimeHeapItem(when, who) );
  339.     }
  340. }
  341.  
  342. //
  343. //    Advance time. Assumes all other CPUs are idle, so no locking
  344. //    on event structures is needed.
  345. //
  346. void
  347. HardwareCpu::advanceTime()
  348. {
  349.     //
  350.     // Find the minimum time over all pending event piles
  351.     //
  352.     double when = MAXFLOAT;
  353.     bool validItem = FALSE;
  354.     for (int i = 0; i < HardwareCpus; i++ ) {
  355.     AwesimeHeap *p = PendingEvents[i];
  356.     if ( ! p -> isEmpty() ) {
  357.         double hapAt = p -> item( p -> minItem() ).key();
  358.         if (hapAt < when) {
  359.         when = hapAt;
  360.         validItem = TRUE;
  361.         }
  362.     }
  363.     }
  364.     
  365.     if ( !validItem ) {
  366.     SimulationTerminated = 1;
  367.     }
  368.     else {
  369.     
  370. #ifndef NDEBUG
  371.     if (HardwareDebugFlag) {
  372.         cerrLock.reserve();
  373.         cerr << name << " ADVANCE TIME TO " << when << "\n" ;
  374.         cerrLock.release();
  375.     }
  376. #endif /* NDEBUG */
  377.     
  378.     assert( CurrentSimulatedTime <= when );
  379.     CurrentSimulatedTime = when;
  380.     }
  381.     //
  382.     // Should be safe to do this -- everyone is waiting for the master
  383.     // to rendezvous
  384.     //
  385.     
  386. #ifndef NDEBUG
  387.     if (HardwareDebugFlag) {
  388.     cerrLock.reserve();
  389.     cerr << name << "Clear TimeAdvanceCounter\n";
  390.     cerrLock.release();
  391.     }
  392. #endif /* NDEBUG */
  393.     
  394.     TimeAdvanceCounter.set(0);
  395. }
  396.  
  397. Thread *
  398. HardwareCpu::remove()
  399. {
  400.     //
  401.     // Check to see if there's a current event. This gets tricky, because
  402.     // we may not want to wait any more if another event comes in.
  403.     //
  404. #ifndef NDEBUG
  405.     if (HardwareDebugFlag) {
  406.     cerrLock.reserve();
  407.     cerr << name << " try to remove thread\n";
  408.     cerrLock.release();
  409.     }
  410. #endif /* NDEBUG */
  411.  
  412.     Thread *threadToExecute = 0;
  413.     
  414.     do { 
  415.     //
  416.     //    System stopped?
  417.     //
  418.     if (SimulationTerminated) {
  419. #ifndef NDEBUG
  420.         if (HardwareDebugFlag) {
  421.         cerrLock.reserve();
  422.         cerr << name << " Simulation terminated\n" ;
  423.         cerrLock.release();
  424.         }
  425. #endif /* NDEBUG */
  426.         return(0);
  427.     }
  428.     
  429.     //
  430.     //    I got something to do?
  431.     //
  432. #ifndef NDEBUG
  433.     if (HardwareDebugFlag) {
  434.         cerrLock.reserve();
  435.         cerr << name;
  436.         cerr << "Check my own current events pile";
  437.         cerr << " (" << CurrentEventsCounter[iYam] << ")\n";
  438.         cerrLock.release();
  439.     }
  440. #endif /* NDEBUG */
  441.     
  442.     myCurrentEventsLock -> reserve();
  443.     
  444.     if ( CurrentEventsCounter[iYam] > 0 ) {
  445.         threadToExecute = myCurrentEvents -> remove();
  446.         CurrentEventsCounter[iYam] --;
  447.         
  448. #ifndef NDEBUG
  449.         if (HardwareDebugFlag) {
  450.         cerrLock.reserve();
  451.         cerr << name;
  452.         cerr << "Found something, now bump events counter\n";
  453.         cerrLock.release();
  454.         }
  455. #endif /* NDEBUG */
  456.         
  457.         GlobalCurrentEventsCounter.add(-1);
  458.     }
  459.     myCurrentEventsLock -> release();
  460.     
  461.     if (threadToExecute == 0) {
  462.         //
  463.         //    Maybe someone else has something to do?
  464.         //
  465.         while ( threadToExecute == 0 && GlobalCurrentEventsCounter.add(0) > 0 ) {
  466. #ifndef NDEBUG
  467.         if ( HardwareDebugFlag ) {
  468.             cerrLock.reserve();
  469.             cerr << name << " Global Events = ";
  470.             cerr << GlobalCurrentEventsCounter.add(0) << "\n";;
  471.             cerrLock.release();
  472.         }
  473. #endif /* NDEBUG */
  474.         
  475.         int ask = iYam;
  476.         do {
  477.             ask++;
  478.             if ( ask >= HardwareCpus ) { // wrap around for fairness
  479.             ask = 0;
  480.             }
  481. #ifndef NDEBUG
  482.             if (HardwareDebugFlag) {
  483.             cerrLock.reserve();
  484.             cerr << name << "Ask " << ask << " about events \n";
  485.             cerrLock.release();
  486.             }
  487. #endif /* NDEBUG */
  488.             //
  489.             // Note that were *not* locking before looking
  490.             // at CurrentEventsCount -- we treat this as a *guess*
  491.             // before bothering to lonk on it.
  492.             //
  493.             if ( CurrentEventsCounter[ask] > 0) {
  494.             CurrentEventsLock[ask].reserve();
  495.             if ( CurrentEventsCounter[ask] > 0) {
  496. #ifndef NDEBUG
  497.                 if (HardwareDebugFlag) {
  498.                 cerrLock.reserve();
  499.                 cerr << name;
  500.                 cerr << "Found one in " << ask << "\n";
  501.                 cerrLock.release();
  502.                 }
  503. #endif /* NDEBUG */
  504.                 threadToExecute = CurrentEvents[ask] -> remove();
  505.                 GlobalCurrentEventsCounter.add(-1);
  506.                 CurrentEventsCounter[ask]--;
  507.             }
  508.             CurrentEventsLock[ask].release();
  509.             }
  510.         } while (ask != iYam && threadToExecute == 0);
  511.         
  512.         if ( threadToExecute == 0 ) {
  513. #ifndef NDEBUG
  514.             if (HardwareDebugFlag) {
  515.             cerrLock.reserve();
  516.             cerr << name;
  517.             cerr << "Did not find anything, may look again";
  518.             cerr << " cnt = ";
  519.             cerr << GlobalCurrentEventsCounter.add(0);
  520.             cerr << "\n";
  521.             cerrLock.release();
  522.             }
  523. #endif /* NDEBUG */
  524.         }
  525.         }
  526.         
  527.         if ( threadToExecute == 0 ) {
  528.         //
  529.         // Ok, we have decided that there is nothing for us to do,
  530.         // and there is nothing for anyone else to do either (maybe).
  531.         // So we need to decide if we are going to advance time or not.
  532.         //
  533.         
  534. #ifndef NDEBUG
  535.         if (HardwareDebugFlag) {
  536.             cerrLock.reserve();
  537.             cerr << name;
  538.             cerr << "Did not find anything, maybe rendezvous\n";
  539.             cerrLock.release();
  540.         }
  541. #endif /* NDEBUG */
  542.         
  543.         int timeAdvanceWas = TimeAdvanceCounter.add(1);
  544.         
  545. #ifndef NDEBUG
  546.         if (HardwareDebugFlag) {
  547.             cerrLock.reserve();
  548.             cerr << name << "increment time advance counter to ";
  549.             cerr << timeAdvanceWas << "\n";
  550.             cerrLock.release();
  551.         }
  552. #endif /* NDEBUG */
  553.         
  554.         assert(timeAdvanceWas <= HardwareCpus);
  555.         //
  556.         // Now, wait for either of TimeAdvanceCounter == HardwareCpus,
  557.         // for a new event
  558.         
  559.         int goAdvanceTime = 0;
  560.         int lookForEvent = 0;
  561.         
  562.         do {
  563. #ifndef NDEBUG
  564.             if (HardwareDebugFlag) {
  565.             cerrLock.reserve();
  566.             cerr << name;
  567.             cerr << "reserve GlobalCurrentEventsCounter";
  568.             cerr << " and TimeAdvanceCounter\n";
  569.             cerrLock.release();
  570.             }
  571. #endif /* NDEBUG */
  572.             
  573.             int global = GlobalCurrentEventsCounter.add(0);
  574.             timeAdvanceWas = TimeAdvanceCounter.add(0);
  575.             
  576.             lookForEvent = global > 0 || SimulationTerminated;
  577.             goAdvanceTime = !lookForEvent
  578.             && timeAdvanceWas == HardwareCpus;
  579.             
  580. #ifndef NDEBUG
  581.             if (HardwareDebugFlag) {
  582.             cerrLock.reserve();
  583.             cerr << name << "lookForEvent = " << int(lookForEvent);
  584.             cerr << " and goAdvanceTime == " << int(goAdvanceTime);
  585.             cerr << " and TimeAdvanceCounter = " << timeAdvanceWas;
  586.             cerr << "\n";
  587.             cerrLock.release();
  588.             }
  589. #endif /* NDEBUG */
  590.             
  591.             if (lookForEvent) {
  592. #ifndef NDEBUG
  593.             if (HardwareDebugFlag) {
  594.                 cerrLock.reserve();
  595.                 cerr << name << "decrement TimeAdvanceCounter\n";
  596.                 cerrLock.release();
  597.             }
  598. #endif /* NDEBUG */
  599.             //
  600.             // Is this a race? I don not think so. I think we need
  601.             // to put our iron out of the file above & then
  602.             // then put it back in if we decide that we want
  603.             // to loop around.
  604.             //
  605.             TimeAdvanceCounter.add(-1);
  606.             }
  607.         } while ( !( goAdvanceTime || lookForEvent ) );
  608.         
  609.         assert( (goAdvanceTime && !lookForEvent)
  610.                || (lookForEvent && !goAdvanceTime) );
  611.         
  612.         if (lookForEvent) {
  613. #ifndef NDEBUG
  614.             if (HardwareDebugFlag) {
  615.             cerrLock.reserve();
  616.             cerr << name << "decided to look for event\n";
  617.             cerrLock.release();
  618.             }
  619. #endif /* NDEBUG */
  620.         }
  621.         else {
  622.             rendezvous();
  623.             
  624.             //
  625.             // Nothing is locked at this point.
  626.             //
  627.             
  628.             if (iYam == 0) {
  629. #ifndef NDEBUG
  630.             if (HardwareDebugFlag) {
  631.             cerrLock.reserve();
  632.             cerr << name << "rendezvous to advance time\n";
  633.             cerrLock.release();
  634.             }
  635. #endif /* NDEBUG */
  636.  
  637.             advanceTime();
  638.             }
  639.             
  640.             //
  641.             // Why the second rendezvous?
  642.             // If tasks are priority ordered, we want to be able
  643.             // to pull them out, order them & then start.
  644.             //
  645.             // Also, advance time depends on this.
  646.             //
  647.             rendezvous();
  648.             
  649.             //
  650.             // Now that we know the time of the minimum entry in the
  651.             // heap, remove all the events which occur at that time
  652.             // or before that time (actually, that is an error).
  653.             //
  654.             // Each process does its own work to reduce overhead.
  655.             // We keep track of how many processes were added to
  656.             // the current events queue and then bump the global
  657.             // events count by that amout.
  658.             //
  659.             // This canot cause race conditions because we only
  660.             // use this info in the rendevzous to advance time
  661.             // code above, and not all cpus will be there yet
  662.             // (i.e. the current cpu is not there)
  663.             //
  664.  
  665. #ifndef NDEBUG
  666.             if (HardwareDebugFlag) {
  667.             cerrLock.reserve();
  668.             cerr << name << "Move pending to active\n";
  669.             cerrLock.release();
  670.             }
  671. #endif /* NDEBUG */
  672.             
  673.             AwesimeHeapItem item;
  674.             AwesimeHeap *p = myPendingEvents;
  675.             ThreadContainer *c = myCurrentEvents;
  676.             int added = 0;
  677.             
  678.             CurrentEventsLock[iYam].reserve();
  679.             
  680.             for (AwesimeHeapIndex index = p -> minItem();
  681.              index != AwesimeHeapNull
  682.              && p -> item(index).key() <= CurrentSimulatedTime;
  683.              index = p -> minItem() )
  684.             {
  685.             bool removed = p -> remove(item);
  686.             assert( removed );
  687.             c -> add((Thread *) item.ptr());
  688.             added++;
  689.             }
  690.  
  691.             CurrentEventsCounter[iYam] += added;
  692.             GlobalCurrentEventsCounter.add(added);
  693.  
  694.             CurrentEventsLock[iYam].release();
  695.             
  696.         }
  697.         }
  698.     }
  699.     } while (threadToExecute == 0);
  700.  
  701.     assert( threadToExecute != 0 ) ;
  702.  
  703. #ifndef NDEBUG
  704.     if (HardwareDebugFlag) {
  705.     cerrLock.reserve();
  706.     cerr << name << "find " << hex(long(threadToExecute)) << "\n";
  707.     cerrLock.release();
  708.     }
  709. #endif /* NDEBUG */
  710.     
  711.     return( threadToExecute );
  712. }
  713.  
  714. void
  715. HardwareCpu::terminateSimulation()
  716. {
  717.     SimulationTerminated = 1;
  718. }
  719.  
  720. //
  721. //    Exception handlers
  722. //
  723. void
  724. HardwareCpu::raise()
  725. {
  726.     assert(currentThread != 0);
  727.     currentThread -> pContext.switchContext( &systemContext );
  728. }
  729.  
  730.  
  731. void
  732. HardwareCpu::delayException( double howLong )
  733. {
  734.     //
  735.     // This duplicates some code in add -- it is done here to speed things
  736.     // up.
  737.     //
  738.  
  739. #ifndef NDEBUG
  740.         if ( HardwareDebugFlag ) {
  741.         cerrLock.reserve();
  742.         cerr << name << " delay context for " << howLong << "\n";
  743.         cerrLock.release();
  744.         }
  745. #endif /* NDEBUG */
  746.  
  747.     if ( howLong > 0 ) {
  748.  
  749. #ifndef NDEBUG
  750.     if ( HardwareDebugFlag ) {
  751.         cerrLock.reserve();
  752.         cerr << name << " place on pending queue\n";
  753.         cerrLock.release();
  754.     }
  755. #endif /* NDEBUG */
  756.  
  757.     assert(currentThread != 0);
  758.  
  759.     howLong += CurrentSimulatedTime;
  760.     myPendingEvents->add( AwesimeHeapItem(howLong, currentThread) );
  761.     myCurrentEventsLock -> reserve();
  762.  
  763.     if ( CurrentEventsCounter[iYam] > 0 ) {
  764.  
  765. #ifndef NDEBUG
  766.         if ( HardwareDebugFlag ) {
  767.         cerrLock.reserve();
  768.         cerr << name << " CurrentEventsCount = ";
  769.         cerr << CurrentEventsCounter[iYam] << "\n";
  770.         cerrLock.release();
  771.         }
  772. #endif /* NDEBUG */
  773.         
  774.         Thread *from = currentThread;
  775.         currentThread = myCurrentEvents -> remove();
  776.         CurrentEventsCounter[iYam]--;
  777.         GlobalCurrentEventsCounter.add(-1);
  778.  
  779.         myCurrentEventsLock -> release();
  780. #ifndef NDEBUG
  781.         if ( HardwareDebugFlag ) {
  782.         cerrLock.reserve();
  783.         cerr << name << " and switch to ";
  784.         cerr << hex(long(currentThread)) << "\n";
  785.         cerr << *currentThread;
  786.         cerrLock.release();
  787.         }
  788. #endif /* NDEBUG */
  789.         from -> pContext.switchContext ( &( currentThread -> pContext ) );
  790.         //
  791.         // The contact that called delayException will resume here
  792.         //
  793.     }
  794.     else {
  795.         //
  796.         // Unable to simply call remove(), because we might advance time
  797.         // or something. However, we have put our self into the pending
  798.         // queue, so we simply need to find a new context.
  799.         //
  800.         myCurrentEventsLock -> release();
  801. #ifndef NDEBUG
  802.         if ( HardwareDebugFlag ) {
  803.         cerrLock.reserve();
  804.         cerr << name << " let CPU switch contexts\n";
  805.         cerr << *currentThread;
  806.         cerrLock.release();
  807.         }
  808. #endif /* NDEBUG */
  809.         raisedBy = ExceptionSwitch;
  810.         raise();
  811.     }
  812.     }
  813.     else {
  814.     //
  815.     // unsafe to add to current events, but then again, there's nothing
  816.     // to do, so don't raise an exception.
  817.     //
  818.     }
  819. }
  820.  
  821. //
  822. // This is the job dispatcher.
  823. //
  824.  
  825. void
  826. HardwareCpu::stirItAround()
  827. {
  828.     currentThread = 0;
  829.  
  830.     while( ! SimulationTerminated ) {
  831.  
  832.     if ( currentThread == 0 ) {
  833.         currentThread = remove();
  834.     }
  835.  
  836.     if ( currentThread != 0 ) {
  837.  
  838. #ifndef NDEBUG
  839.         if (HardwareDebugFlag || currentThread -> debug()) {
  840.         cerrLock.reserve();
  841.         cerr << name << " switch to " << *currentThread << "\n";
  842.         cerrLock.release();
  843.         }
  844. #endif /* NDEBUG */
  845.  
  846.         systemContext.switchContext(&(currentThread -> pContext));
  847.  
  848.         if ( currentThread != 0 &&
  849.         (HardwareDebugFlag || currentThread -> debug() )) {
  850.             cerr << name << " Raise by " << *currentThread << "\n";
  851.         }
  852.         //
  853.         // Come back here because of an exception
  854.         //
  855.         switch (raisedBy) {
  856.  
  857.         case ExceptionReserve :
  858. #ifndef NDEBUG
  859.         if (HardwareDebugFlag) {
  860.             cerrLock.reserve();
  861.             cerr << name << "reserve exception\n";
  862.             cerrLock.release();
  863.         }
  864. #endif /* NDEBUG */
  865.         bool blocked = 
  866.             reserveToBlockOn -> reserveByException( currentThread );
  867.         if ( blocked ) {
  868.             currentThread = 0;
  869.         }
  870.         break;
  871.  
  872.         case ExceptionDelay:
  873. #ifndef NDEBUG
  874.         if (HardwareDebugFlag) {
  875.             cerrLock.reserve();
  876.             cerr << name << "delay exception for ";
  877.             cerr << timeToDelay << "\n";
  878.             cerrLock.release();
  879.         }
  880. #endif /* NDEBUG */
  881.         add( currentThread, timeToDelay );
  882.         currentThread = 0;
  883.         break;
  884.  
  885.         case ExceptionSwitch:
  886. #ifndef NDEBUG
  887.         if (HardwareDebugFlag) {
  888.             cerrLock.reserve();
  889.             cerr << name << " switch exception\n";
  890.             cerrLock.release();
  891.         }
  892. #endif /* NDEBUG */
  893.  
  894.         currentThread = 0;
  895.         break;
  896.  
  897.         case ExceptionTerminateThread:
  898. #ifndef NDEBUG
  899.         if (HardwareDebugFlag) {
  900.             cerrLock.reserve();
  901.             cerr << name << "termination exception for ";
  902.             cerr << hex(long(threadToTerminate)) << "\n";
  903.             cerr << *threadToTerminate <<"\n";
  904.             cerrLock.release();
  905.         }
  906. #endif /* NDEBUG */
  907.  
  908.         if ( threadToTerminate == currentThread ) {
  909.             currentThread = 0;
  910.             delete threadToTerminate;
  911.         }
  912.         else {
  913.             delete threadToTerminate;
  914.         }
  915.         break;
  916.  
  917.         default:
  918.         cerrLock.reserve();
  919.         cerr << name << "Unknown exception:";
  920.         cerr << int(raisedBy) << "\n";
  921.         cerrLock.release();
  922.         exit(1);
  923.         break;
  924.         
  925.         }
  926.     }
  927.     }
  928. }
  929. @
  930.  
  931.  
  932. 1.2
  933. log
  934. @*** empty log message ***
  935. @
  936. text
  937. @d2 1
  938. a8 2
  939. #include "SharedMemory.h"
  940. #include "SharedMalloc.h"
  941. d45 6
  942. d71 3
  943. a73 3
  944. static HardSpinLock CurrentEventsLock[HardwareCpusMax];
  945. static int CurrentEventsCounter[HardwareCpusMax];
  946. static ThreadContainer *CurrentEvents[HardwareCpusMax];
  947. d78 1
  948. a78 1
  949. static AwesimeHeap *PendingEvents[HardwareCpusMax];
  950. d176 4
  951. d191 1
  952. d497 3
  953. a499 3
  954.         // Ok, we've decided that there's nothing for us to do,
  955.         // and there's nothing for anyone else to do either (maybe).
  956.         // So we need to decide if we're going to advance time or not.
  957. d590 1
  958. d596 1
  959. d604 1
  960. a604 3
  961.             rendezvous();
  962.             
  963.             if (iYam == 0) {
  964. d627 2
  965. a628 2
  966.             // This can't cause race conditions because we only
  967.             // use this info in the ``rendevzous to advance time''
  968. d815 5
  969. a895 6
  970. }
  971.  
  972. ThreadContainer *
  973. AllocateHardwareCurrentEventsStructure()
  974. {
  975.     return( new HeapScheduler(32) );
  976. @
  977.  
  978.  
  979. 1.1
  980. log
  981. @Initial revision
  982. @
  983. text
  984. @d3 1
  985. d10 1
  986. d28 1
  987. d57 4
  988. a60 3
  989. static HardSpinLock CurrentEventsLock;
  990. static int SimulationTerminated = 0;
  991. static HeapScheduler CurrentEvents;
  992. d62 7
  993. a68 2
  994. static HardSpinLock PendingEventsLock;
  995. static AwesimeHeap PendingEvents;
  996. d70 6
  997. a76 2
  998. static int TimeAdvanceCounter = 0;
  999. static HardSpinLock TimeAdvanceCounterLock;
  1000. d78 2
  1001. d83 1
  1002. a83 1
  1003. static HardwareDebugFlag = 0;
  1004. d91 1
  1005. a91 1
  1006.     name = "[HardwareCpu-0] ";
  1007. d117 50
  1008. a172 1
  1009.     CpuBarrier.height(cpus);
  1010. d174 1
  1011. d180 1
  1012. a182 1
  1013.     HardwareMemoryAllocator.disableFurtherBreaks();
  1014. d190 1
  1015. d196 11
  1016. a206 7
  1017.     for (int whoAmI = HardwareCpus - 1; whoAmI > 0; whoAmI--) {
  1018.     int pid = fork();
  1019.     if (pid == 0) {
  1020.         iYam = whoAmI;
  1021.         sprintf(nameSpace, "[HardwareCpu-%d] ", whoAmI);
  1022.         name = nameSpace;
  1023.         break;
  1024. d210 1
  1025. d216 2
  1026. d258 1
  1027. d264 1
  1028. d268 15
  1029. a282 3
  1030.     CurrentEventsLock.reserve();
  1031.     CurrentEvents.add( who );
  1032.     CurrentEventsLock.release();
  1033. d285 1
  1034. d291 1
  1035. d296 1
  1036. a296 3
  1037.     PendingEventsLock.reserve();
  1038.     PendingEvents.add( AwesimeHeapItem(when, who) );
  1039.     PendingEventsLock.release();
  1040. d300 4
  1041. d308 1
  1042. a308 1
  1043.     //    Just for safety
  1044. d310 13
  1045. a322 6
  1046.     PendingEventsLock.reserve();
  1047.     CurrentEventsLock.reserve();
  1048.     
  1049.     AwesimeHeapItem item;
  1050.     int validItem = PendingEvents.remove( item );
  1051.     
  1052. d328 1
  1053. a328 4
  1054.     double when = item.key();
  1055.     assert( CurrentSimulatedTime <= when );
  1056.     CurrentSimulatedTime = when;
  1057.     
  1058. d334 1
  1059. d336 2
  1060. a337 28
  1061.     CurrentEvents.add( (Thread*) item.ptr() );
  1062.     //
  1063.     // Now that we know the time of the minimum entry in the
  1064.     // heap, remove all the events which occur at that time
  1065.     // or before that time (actually, that is an error).
  1066.     //
  1067.     // This allows the items that occur at the same time
  1068.     // (in the heap) to be ordered in the subscheduler
  1069.     // according to the constraints of the subscheduler
  1070.     // (.e.g heapscheduler).
  1071.     //
  1072.     // If we did not pull out all items for the current time,
  1073.     // it is possible that a threads will execute out of
  1074.     // priority order. This could be fixed by making the
  1075.     // ThreadHeap properly order events, but that also
  1076.     // means we have got a single central data structure,
  1077.     // and there will be more contention.
  1078.     //
  1079.     for (AwesimeHeapIndex index = PendingEvents.minItem();
  1080.          index != AwesimeHeapNull
  1081.          && PendingEvents.item(index).key() <= when;
  1082.          index = PendingEvents.minItem() )
  1083.     {
  1084.         
  1085.         bool removed = PendingEvents.remove(item);
  1086.         assert( removed );
  1087.         CurrentEvents.add((Thread *) item.ptr());
  1088.     }
  1089. a338 1
  1090.  
  1091. d340 1
  1092. a340 1
  1093.     // Should be save to do this -- everyone is waiting for the master
  1094. d343 2
  1095. a344 1
  1096.  
  1097. d350 3
  1098. a352 8
  1099.  
  1100.     TimeAdvanceCounter = 0;
  1101.  
  1102.     //
  1103.     // Release the locks on the two data structures
  1104.     //
  1105.     CurrentEventsLock.release();
  1106.     PendingEventsLock.release();
  1107. d362 1
  1108. d368 1
  1109. d370 6
  1110. a375 5
  1111.     CurrentEventsLock.reserve();
  1112.  
  1113.     while ( CurrentEvents.isEmpty() ) {
  1114.     CurrentEventsLock.release();
  1115.  
  1116. d377 1
  1117. d383 1
  1118. d386 5
  1119. a390 5
  1120.  
  1121.     TimeAdvanceCounterLock.reserve();
  1122.  
  1123.     TimeAdvanceCounter++;
  1124.  
  1125. d393 3
  1126. a395 2
  1127.         cerr << name << "increment time advance counter to";
  1128.         cerr << TimeAdvanceCounter << "\n";
  1129. d398 9
  1130. a406 13
  1131.  
  1132.     assert(TimeAdvanceCounter <= HardwareCpus);
  1133.  
  1134.     TimeAdvanceCounterLock.release();
  1135.  
  1136.     //
  1137.     // Now, wait for either of TimeAdvanceCounter == HardwareCpus,
  1138.     // for a new event
  1139.  
  1140.     int goAdvanceTime = 0;
  1141.     int lookForEvent = 0;
  1142.  
  1143.     do {
  1144. d409 2
  1145. a410 1
  1146.         cerr << name << "reserve CurrentEventsLock\n";
  1147. d413 70
  1148. a482 5
  1149.         CurrentEventsLock.reserve();
  1150.         if (HardwareDebugFlag) {
  1151.         cerrLock.reserve();
  1152.         cerr << name << "reserve TimeAdvanceCounterLock\n";
  1153.         cerrLock.release();
  1154. d484 9
  1155. a492 16
  1156.         TimeAdvanceCounterLock.reserve();
  1157.  
  1158.         lookForEvent = !CurrentEvents.isEmpty() || SimulationTerminated;
  1159.         goAdvanceTime = !lookForEvent
  1160.         && TimeAdvanceCounter == HardwareCpus;
  1161.  
  1162.         if (HardwareDebugFlag) {
  1163.         cerrLock.reserve();
  1164.         cerr << name << "lookForEvent = " << int(lookForEvent);
  1165.         cerr << " and goAdvanceTime == " << int(goAdvanceTime);
  1166.         cerr << " and TimeAdvanceCounter = " << TimeAdvanceCounter;
  1167.         cerr << "\n";
  1168.         cerrLock.release();
  1169.         }
  1170.  
  1171.         if (lookForEvent) {
  1172. d495 2
  1173. a496 1
  1174.             cerr << name << "decrement TimeAdvanceCounter\n";
  1175. d498 124
  1176. a621 3
  1177.         }        
  1178.         TimeAdvanceCounter--;
  1179.         }
  1180. d623 25
  1181. a647 2
  1182.         TimeAdvanceCounterLock.release();
  1183.         CurrentEventsLock.release();
  1184. d649 2
  1185. a650 1
  1186.     } while ( !( goAdvanceTime || lookForEvent ) );
  1187. d652 3
  1188. a654 8
  1189.     assert( (goAdvanceTime && !lookForEvent)
  1190.            || (lookForEvent && !goAdvanceTime) );
  1191.  
  1192.     if (lookForEvent) {
  1193.         if (HardwareDebugFlag) {
  1194.         cerrLock.reserve();
  1195.         cerr << name << "decided to look for event\n";
  1196.         cerrLock.release();
  1197. a655 2
  1198.         CurrentEventsLock.reserve();
  1199.         continue; /* while CurrentEvents.isEmpty() */
  1200. d657 1
  1201. a657 15
  1202.     
  1203.     //
  1204.     // Nothing is locked at this point.
  1205.     //
  1206.     
  1207.     if (HardwareDebugFlag) {
  1208.         cerrLock.reserve();
  1209.         cerr << name << "rendezvous to advance time\n";
  1210.         cerrLock.release();
  1211.     }
  1212.     rendezvous();
  1213.     if (iYam == 0) {
  1214.         advanceTime();
  1215.     }
  1216.     rendezvous();
  1217. d659 1
  1218. a659 5
  1219.     //
  1220.     // reserve for next trip around loop
  1221.     //
  1222.     CurrentEventsLock.reserve();
  1223.     }
  1224. d661 5
  1225. a665 3
  1226.     if ( SimulationTerminated ) {
  1227.     CurrentEventsLock.release();
  1228.     return(0);
  1229. d667 3
  1230. a669 15
  1231.     else {
  1232.     //
  1233.     // We have the CurrentEventsLock & there should be someone there.
  1234.     //
  1235.     
  1236.     Thread *newGuy = CurrentEvents.remove();
  1237.     CurrentEventsLock.release();
  1238.     if (HardwareDebugFlag) {
  1239.         cerrLock.reserve();
  1240.         cerr << name << "find " << hex(long(newGuy)) << "\n";
  1241.         cerrLock.release();
  1242.     }
  1243.     
  1244.     return( newGuy );
  1245.     }
  1246. a674 1
  1247.     CurrentEventsLock.reserve();
  1248. a675 1
  1249.     CurrentEventsLock.release();
  1250. a687 7
  1251. void
  1252. HardwareCpu::reserveByException( ReserveByException *sem )
  1253. {
  1254.     raisedBy = ExceptionReserve;
  1255.     reserveToBlockOn = sem;
  1256.     raise();
  1257. }
  1258. d690 1
  1259. a690 1
  1260. HardwareCpu::threadTerminateException( Thread *killMe )
  1261. d692 4
  1262. a695 4
  1263.     raisedBy = ExceptionTerminateThread;
  1264.     threadToTerminate = killMe;
  1265.     raise();
  1266. }
  1267. d697 80
  1268. a776 6
  1269. void
  1270. HardwareCpu::delayException( double howLong )
  1271. {
  1272.     raisedBy = ExceptionDelay;
  1273.     timeToDelay = howLong;
  1274.     raise();
  1275. d796 1
  1276. d802 1
  1277. d811 1
  1278. d817 1
  1279. d826 1
  1280. d833 1
  1281. d838 12
  1282. d851 1
  1283. d859 1
  1284. d881 6
  1285. @
  1286.